package com.bb.blog.code.zk;

import com.weicoder.common.W;
import org.apache.zookeeper.*;
import org.apache.zookeeper.data.Stat;
import org.redisson.api.RLock;

import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.locks.AbstractQueuedSynchronizer;
import java.util.concurrent.locks.LockSupport;
import java.util.stream.Collectors;

public class ZkLock extends ZkClient {

    protected  String rootPath = "/bbLock";
    private String lockName;
    private String fullPath ;
    private String nodeName;
    private Stat nodeStat;
    private Thread t;

    private AtomicInteger state = new  AtomicInteger(0);
    public ZkLock(String lockName){
        this.lockName = lockName;
        this.fullPath = rootPath + "/" + lockName;
        this.t = Thread.currentThread();
        this.nodeStat = new Stat();
        // init root path
        init();

    }

    public void init(){
        try {
            if (zk.exists(rootPath, false) == null) {
                zk.create(rootPath,null, ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);
            }
            if(zk.exists(fullPath,false) == null){
                zk.create(fullPath, null,ZooDefs.Ids.OPEN_ACL_UNSAFE,CreateMode.PERSISTENT);
            }

        } catch (InterruptedException | KeeperException e) {
            logger.info("初始化异常",e);
        }
    }

    public void lock(){
        if(!Thread.currentThread().equals(t)){
            throw new RuntimeException("8行 Lock对象线程间不共享！");
        }

        if (state.get() > 0){
            state.incrementAndGet();
            return ;
        }

        try {
            this.nodeName = zk.create(fullPath + "/", null, ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL_SEQUENTIAL,this.nodeStat);
            checkLock();

        } catch (KeeperException e) {
            e.printStackTrace();
        } catch (InterruptedException e) {
            throw  new RuntimeException();
        }

    }

    private void checkLock() {
        while(true){
            List<String> nodes = null;
            try {
                nodes = zk.getChildren(fullPath,false).stream().sorted().map(p->{
                    p = fullPath + "/" + p;
                    return p;
                }).collect(Collectors.toList());
            } catch (KeeperException e) {
                e.printStackTrace();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            for (int i = 0; i <nodes.size(); i++) {
                if(nodeName.equals(nodes.get(i))){
                    if (i == 0){
                        System.out.println(t.getName() + "老子获取到锁了");
                        return ;
                    }else{
                        watch(nodes.get(i-1));
                        LockSupport.park();
                        break;
                    }
                }
            }
        }

    }

    private void watch(String p) {
        try {
            zk.addWatch(p, new Watcher() {
                @Override
                public void process(WatchedEvent event) {
                    if (event.getType().equals(Event.EventType.NodeDeleted)) {
                        LockSupport.unpark(t);
                    }
                }
            },AddWatchMode.PERSISTENT);
        } catch (KeeperException e) {
            e.printStackTrace();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    public void unlock(){
        if(state.decrementAndGet()>0){
            return ;
        }
        try {
            zk.delete(nodeName,this.nodeStat.getVersion());
            zk.close();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (KeeperException e) {
            e.printStackTrace();
        }
        System.out.println(t.getName()+"老子放掉了锁");

    }

    public static void main(String[] args) {
        ExecutorService executorService = Executors.newFixedThreadPool(10);
        for (int i = 0; i < 3; i++) {
            executorService.execute(new Runnable() {
                @Override
                public void run() {
                    ZkLock zkLock = new ZkLock("ceshi");
                    zkLock.lock();
                    try {
                        System.out.println("假装工作1s");
                        Thread.sleep(1000);

                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    zkLock.unlock();
                }
            });
        }

    }




}
